import re
import wsgiref.util
from urllib.request import url2pathname
from purest.web.util import MultiValueDict

# TODO add bodyReader as __init__ param
class Request:
    
    _charset_pattern = re.compile(".*charset=([^\s;]*).*")
    
    def __init__(self, environ):
        assert environ is not None
        
        def extract_path_params():
            result = {}
            if "wsgiorg.routing_args" in environ:
                result = environ["wsgiorg.routing_args"][1]
            return result
        
        def extract_query_params(environ):
            """ Returns util.MultiValueDict with params from query string."""
            query_params = MultiValueDict()
            query_string = url2pathname(environ.get("QUERY_STRING", ""))
            for param in query_string.split("&"):
                key_and_value = param.split("=")
                key = key_and_value[0]
                query_params[key] = \
                    key_and_value[1] if len(key_and_value) > 1 else None
            return query_params        
        
        def extract_http_headers(environ):
            """ Extracts HTTP headers from environ and returns them as map. """
            headers = {}
            for key in filter(lambda key: key.startswith("HTTP_"), environ):
                key_without_prefix = key[5:]
                headers[key_without_prefix] = environ[key]
            return headers
        
        def extract_cookies(environ):
            """ Returns a dictionary with cookie names (as keys) and values. """
            cookies = {}
            if "HTTP_COOKIE" in environ:
                for cookie_string in environ["HTTP_COOKIE"].split(";"):
                    key, value = cookie_string.split("=")
                    cookies[key.strip()] = value.replace('"', '')
            return cookies
        
        def extract_content_encoding(content_type):
            if content_type is None:
                return None
            matcher = Request._charset_pattern.match(content_type)
            return matcher.groups(0) if matcher else None
         
        # Fields required by the spec are accessed without 'get(key, default)',
        # because it can be expected that they exist.               
        self.environ = environ
        self.http_method = environ["REQUEST_METHOD"]
        self.url_scheme = environ.get("wsgi.url_scheme", None)
        self.uri = wsgiref.util.request_uri(environ)
        self.path = environ["PATH_INFO"]
        self.path_params = extract_path_params()
        self.query_params = extract_query_params(environ)
        self.headers = extract_http_headers(environ)
        self.cookies = extract_cookies(environ)
        self.content_length = environ.get("CONTENT_LENGTH", None)
        self.content_type = environ.get("CONTENT_TYPE", None)
        self.content_encoding = extract_content_encoding(self.content_type)
        self.body = environ["wsgi.input"]
        self.server_name = environ["SERVER_NAME"]
        self.server_port = environ["SERVER_PORT"]
        self.protocol = environ.get("SERVER_PROTOCOL", None)
        self.remote_user = environ.get("REMOTE_USER", None)
        self.remote_address = environ.get("REMOTE_ADDR", None)
        self.is_secure = environ["wsgi.url_scheme"] == "https"
